package com.sxmfyy.common.config;


import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.util.concurrent.RateLimiter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.concurrent.TimeUnit;

/**
 * Guava令牌桶缓存配置类
 * @author GongXiaoHui
 * @since 2025/11/10 15:17
 */
@Configuration
public class GuavaCacheConfig {

    /**
     * 限流缓存最大条数（1万条）
     */
    public static final int RATE_LIMIT_MAX_SIZE = 10000;

    /**
     * 限流缓存过期时间（30分钟）
     */
    private static final int RATE_LIMIT_EXPIRE_SECONDS = 30 * 60;

    /**
     * 防重复提交最大条数（5千条）
     */
    public static final int REPEAT_SUBMIT_MAX_SIZE = 5000;

    /**
     * 防重复提交过期时间（访问后过期避免阻塞-10秒）
     */
    private static final int REPEAT_SUBMIT_EXPIRE_SECONDS = 10;

    /**
     * 创建令牌桶缓存
     * @return 令牌桶缓存实例
     */
    @Bean
    public Cache<String, RateLimiter> rateLimitCache() {
        // 创建令牌桶缓存
        return buildCache(RATE_LIMIT_MAX_SIZE, RATE_LIMIT_EXPIRE_SECONDS);
    }

    /**
     * 创建防重复提交缓存
     * @return 防重复提交缓存实例
     */
    @Bean
    public Cache<String, Boolean> repeatSubmitCache() {
        return buildCache(REPEAT_SUBMIT_MAX_SIZE, REPEAT_SUBMIT_EXPIRE_SECONDS);
    }

    /**
     * 构建通用 Guava Cache
     * @param maximumSize 最大缓存条目（防 OOM）
     * @param expireAfterAccessSeconds 访问后过期时间（秒，清理闲置数据）
     * @param <K> 缓存 Key 类型
     * @param <V> 缓存 Value 类型
     * @return 配置好的 Guava Cache 实例
     */
    private <K, V> Cache<K, V> buildCache(int maximumSize, int expireAfterAccessSeconds) {
        // 校验参数合法性（避免配置错误）
        if (maximumSize <= 0) {
            throw new IllegalArgumentException("缓存最大条目 maximumSize 必须大于 0");
        }
        if (expireAfterAccessSeconds <= 0) {
            throw new IllegalArgumentException("过期时间 expireAfterAccessSeconds 必须大于 0");
        }

        return CacheBuilder.newBuilder()
                // 共用配置：并发级别（默认=CPU核心数，优化并发访问性能）
                .concurrencyLevel(Runtime.getRuntime().availableProcessors())
                // 共用配置：开启缓存统计（命中率、淘汰数等，便于监控优化）
                .recordStats()
                // 定制化：最大缓存条目（由调用方指定，适配不同场景）
                .maximumSize(maximumSize)
                // 定制化：访问后过期（由调用方指定，适配不同场景）
                .expireAfterAccess(expireAfterAccessSeconds, TimeUnit.SECONDS)
                // 可选：设置缓存创建/更新后的弱引用（进一步优化内存，按需开启）
                // .weakValues()
                .build();
    }
}